#include "stdafx.h"
#include "CppUnitTest.h"

#include "System/Utility/Testing.h"
#include "System/Base/Integer.h"
#include "System/Base/Array.h"
#include "System/Base/ArrayIterator.h"
#include "System/Base/Range.h"
#include "System/Base/String.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Native::System;
using namespace Native { namespace System::Utility;

namespace TestNativeSystem
{
    TEST_CLASS(Array_Tester)
    {
    public:
        int32_t _filled_value;

        Array_Tester() :
            _filled_value(10)
        {
        }

        TEST_METHOD(Array_ConstructDefault)
        {
            CArray<Int32s> array;

            Assert::AreEqual(array.Count(), 0u);
        }

        TEST_METHOD(Array_ConstructedByPointer)
        {
            Int32s int32s_array[3] = {Int32s(_filled_value), Int32s(_filled_value+1), Int32s(_filled_value+2)};

            CArray<Int32s> array(int32s_array, 2);

            Assert::AreEqual(array.Count(), 2u);
            Assert::AreEqual(array[0].Value(), _filled_value);
        }

        TEST_METHOD(Array_AppendData)
        {
            CArray<Int32s> array;

            Assert::AreEqual(array.Append(Int32s(1)).Count(), 1u);
            Assert::AreEqual(array.Append(Int32s(2)).Count(), 2u);
        }

        TEST_METHOD(Array_ChangeData)
        {
            CArray<Int32s> array;

            array.Append(Int32s(_filled_value));
            Assert::AreEqual(array[0].Value(), _filled_value);

            array[0] = Int32s(_filled_value+100);
            Assert::AreEqual(array[0].Value(), _filled_value+100);

            function<void(void)> throw_exception_1 = [] {
                CArray<Int32s> array;

                array[11];
            };
            Assert::ExpectException<CException>(throw_exception_1);

            function<void(void)> throw_exception_2 = [&] {
                CArray<Int32s> array;

                array.Append(Int32s(_filled_value));

                array[11];
            };
            Assert::ExpectException<CException>(throw_exception_2);
        }

        TEST_METHOD(Array_DetectPosition)
        {
            CArray<Int32s> array;

            array.Append(Int32s(1));
            array.Append(Int32s(2));
            array.Append(Int32s(3));

            Assert::IsTrue(array.AtBeginning(0));
            Assert::IsFalse(array.AtEnding(0));
            Assert::IsFalse(array.AtBeginning(1));
            Assert::IsFalse(array.AtEnding(1));
            Assert::IsFalse(array.AtBeginning(2));
            Assert::IsTrue(array.AtEnding(2));
        }

        TEST_METHOD(Array_ConstructCursor)
        {
            CArrayCursor existing_cursor(1);
            CArrayCursor inexistent_cursor(CArrayCursor::INEXISTENT);

            Assert::IsTrue(existing_cursor.Exist());
            Assert::AreEqual(existing_cursor.Index(), 1u);
            Assert::IsFalse(inexistent_cursor.Exist());
            Assert::AreEqual(inexistent_cursor.Index(), CArrayCursor::INEXISTENT);
        }

        TEST_METHOD(Array_LocateElement)
        {
            CArray<Int32s> array;

            array.Append(Int32s(1));
            array.Append(Int32s(2));
            array.Append(Int32s(3));

            auto testee = array.At(1);

            Assert::IsTrue(testee.Exist());
            Assert::AreEqual(testee.Index(), 1u);
        }

        TEST_METHOD(Array_LocateFirstElement)
        {
            CArray<Int32s> array;
            CArray<Int32s> empty_array;

            array.Append(Int32s(1));
            array.Append(Int32s(2));
            array.Append(Int32s(3));

            auto cursor = array.LocateFirst();
            auto empty_cursor = empty_array.LocateFirst();

            Assert::IsTrue(cursor.Exist());
            Assert::IsTrue(cursor.Index() == 0);
            Assert::IsFalse(empty_cursor.Exist());
            Assert::AreEqual(empty_cursor.Index(), CArrayCursor::INEXISTENT);
        }

        TEST_METHOD(Array_LocateThenGoForward)
        {
            CArray<Int32s> array;

            array.Append(Int32s(1));
            array.Append(Int32s(2));

            auto cursor = array.LocateFirst();

            Assert::IsTrue(cursor.Exist());

            auto forward = cursor.Forward();

            Assert::IsTrue(forward);
            Assert::IsTrue(cursor.Index() == 1);

            forward = cursor.Forward();

            Assert::IsTrue(forward);
            Assert::IsTrue(cursor.Index() == 2);
        }

        TEST_METHOD(Array_SelectData)
		{
			CArray<CScene> array;
            wstring class_condition(L"Interage");

            array.Append(CScene(L"CString", L"Append", 789));
            array.Append(CScene(L"Interage", L"Value", 120));
            array.Append(CScene(L"Interage", L"ToString", 32));
            array.Append(CScene(L"CCase", L"Message", 45));

            auto have = [&](C_SCENE& data){
                return data.Class() == class_condition;
            };

            auto selected = array.Select(have);

            Assert::AreEqual(selected.size(), 2u);

            for(int i = 0; i < selected.size(); i++) {
                Assert::AreEqual(selected[i].Class(), class_condition);
            }
		}
    };
}